﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace WizzardTheGame
{
    class GameWorld
    {
        public const String STANDARD_PLAYER_MODEL = "Models\\warlock";
        public const float STANDARD_ENEMY_Z = 0f;
        public static Vector3 STANDARD_ROTATION = new Vector3(MathHelper.PiOver2, 0, 0); // Passer til: Kenneths kasse?
        public static Vector3 STANDARD_ROTATION2 = new Vector3(MathHelper.Pi, MathHelper.Pi + MathHelper.PiOver2, 0); // Passer til: edderkoppen
        private static GameWorld gameworld = null;
        private Camera camera;
        private SpriteBatch spriteBatch;
        private ContentManager content;
        private GraphicsDevice graphics;
        private List<IDrawable> drawables;
        private ObjectText caption;
        private int level;
        private bool bossArea;
        private Player player;
        private List<Enemy> enemies;
        private Boss boss;
        private List<Item> items;
        private List<GameEnvironment> gameEnvironment;
        private bool paused;
        private Object2D background;
        private WeaponMenu weaponMenu;
        private KeyboardState prevKeyboardState;
        private KeyboardState keyboardState;
        private GamePadState prevGamePadState;
        private GamePadState gamePadState;

        #region Properties

        public GamePadState PrevGamePadState
        {
            get { return prevGamePadState; }
            set { prevGamePadState = value; }
        }

        public GamePadState GamePadState
        {
            get { return gamePadState; }
            set { gamePadState = value; }
        }

        public KeyboardState KeyboardState
        {
            get { return keyboardState; }
            set { keyboardState = value; }
        }

        public KeyboardState PrevKeyboardState
        {
            get { return prevKeyboardState; }
            set { prevKeyboardState = value; }
        }

        public Camera Camera {
            get { return camera; }
            private set { camera = value; }
        }

        public SpriteBatch SpriteBatch{
            get { return spriteBatch; }
            private set { spriteBatch = value; }
        }

        public ContentManager Content {
            get { return content; }
            private set { content = value; }
        }

        public GraphicsDevice Graphics
        {
            get { return graphics; }
            private set { graphics = value; }
        }

        public List<IDrawable> Drawables {
            get { return drawables; }
            private set { drawables = value; }
        }

        public ObjectText Caption {
            get { return caption; }
            set { caption = value; }
        }

        public int Level {
            get { return level; }
            private set { level = value; }
        }

        public bool BossArea {
            get { return bossArea; }
            set { bossArea = value; }
        }

        public Player Player {
            get { return player; }
            private set { player = value; }
        }

        public List<Enemy> Enemies {
            get { return enemies; }
            private set { enemies = value; }
        }

        public Boss Boss {
            get { return boss; }
            private set { boss = value; }
        }

        public List<Item> Items {
            get { return items; }
            private set { items = value; }
        }

        public List<GameEnvironment> GameEnvironment {
            get { return gameEnvironment; }
            private set { gameEnvironment = value; }
        }

        public bool Paused {
            get { return paused; }
            set { paused = value; }
        }

        public Object2D Background
        {
            get { return background; }
            set { background = value; }
        }

        public WeaponMenu WeaponMenu
        {
            get { return weaponMenu; }
            set { weaponMenu = value; }
        }

        #endregion

        private GameWorld()
        {
            Drawables = new List<IDrawable>();
            GameEnvironment = new List<GameEnvironment>();
            Items = new List<Item>();
            Paused = false;
        }

        public static GameWorld getInstance()
        {
            if (gameworld == null)
            {
                gameworld = new GameWorld();
            }
            return gameworld;  
        }

        public void Initialize(ContentManager content, GraphicsDevice graphics, SpriteBatch spriteBatch)
        {
            Content = content;
            Graphics = graphics;
            SpriteBatch = spriteBatch;
            background = new Object2D();
            background.Sprite = Content.Load<Texture2D>("Sprites\\Background2");
            background.SetPos(0, 0);
            background.Rectangle = new Rectangle(0, 0, graphics.Viewport.Width, graphics.Viewport.Height);
            Background.IsVisible = true;
            Caption = new ObjectText();
            //har ikke old English fonten vh emil
            Caption.Font = content.Load<SpriteFont>("Fonts\\Verdana");
            Caption.Position = new Vector2(0.1f, 0.1f);
            Caption.Color = Color.Azure;
            Caption.AlphaValue = 255;
            Caption.IsVisible = true;
        }

        public void PlayerInitialize() //Bliver kaldt fra bunden af LoadLevel()
        {
            //Han får lige gratis våben og armor
            Weapon testweapon = new Weapon();
            testweapon.ItemModel.LoadContent("Models\\medieval_sword");
            testweapon.ItemModel.Scale = 20f;
            testweapon.AttackPowerBonus = 100;
            Player.EquippedWeapon = testweapon;
            Player.Inventory.AddItem(testweapon);

            testweapon = new Weapon();
            testweapon.ItemModel.LoadContent("Models\\mace");
            testweapon.ItemModel.Scale = 0.2f;
            testweapon.AttackPowerBonus = 59;
            Player.Inventory.AddItem(testweapon);

            Armor testarmor = new Armor();
            testarmor.ItemModel.LoadContent("Models\\RoundShield");
            testarmor.ItemModel.Scale = 0.1f;
            testarmor.DefenceBonus = 10;
            Player.EquippedArmor = testarmor;
            Player.Inventory.AddItem(testarmor);

            Player.Hpbar.IsVisible = true;
            Player.Hpbar.CalcHP(Player.MaxHP, Player.CurrentHP);
        }

        public void Update()
        {
            PrevKeyboardState = KeyboardState;
            KeyboardState = Keyboard.GetState();
            PrevGamePadState = GamePadState;
            GamePadState = GamePad.GetState(0);
            Player.Update();
            Camera.Update();
            for(int i = 0; i < Enemies.Count; i++)
            {
                if(Enemies[i] != null)Enemies[i].Update();
            }
            WeaponMenu.Update();

        }

        public void Draw(GameTime gameTime)
        {
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.SaveState);
            background.Draw();
            spriteBatch.End();
            foreach (IDrawable item in Drawables)
            {
                item.Draw();
            }
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.SaveState);
            Caption.Draw(gameTime);
            Player.Hpbar.Draw();
            WeaponMenu.Draw();
            Player.PlayerCaption.Draw();
            spriteBatch.End();
        }

        public void hideGameLevel()
        {
            Player.IsAlive = false;
            foreach (Enemy enemy in Enemies)
            {
                enemy.IsAlive = false;
            }
            foreach (GameEnvironment gameEnv in GameEnvironment)
            {
                gameEnv.IsVisible = false;
            }
            Caption.IsVisible = false;
            Player.Hpbar.IsVisible = false;
        }

        public void showGameLevel()
        {
            Player.IsAlive = true;
            foreach (Enemy enemy in Enemies)
            {
                enemy.IsAlive = true;
            }
            foreach (GameEnvironment gameEnv in GameEnvironment)
            {
                gameEnv.IsVisible = true;
            }
            Caption.IsVisible = true;
            Player.Hpbar.IsVisible = true;
        }

        public void createMenues()
        {
            WeaponMenu = new WeaponMenu();
            WeaponMenu.ShownWeapon = Player.EquippedWeapon;

            ObjectText op = new ObjectText();
            op.Text = "Next weapon";
            op.Font = Content.Load<SpriteFont>("Fonts\\MenuText");
            op.Color = Color.Gray;
            op.AlphaValue = 255;
            op.Position = new Vector2(100,30);
            op.IsVisible = true;
            MenuItem mi = new MenuItem();
            mi.Text = op;
            mi.Activate += delegate()
            {
                int i = Player.Inventory.Weapons.IndexOf(WeaponMenu.ShownWeapon);
                if (i < Player.Inventory.Weapons.Count-1)
                {
                    WeaponMenu.ShownWeapon = Player.Inventory.Weapons[i + 1];
                }
                else
                {
                    WeaponMenu.ShownWeapon = Player.Inventory.Weapons[0];
                }
            };
            WeaponMenu.Options.Add(mi);

            op = new ObjectText();
            op.Text = "Previous weapon";
            op.Font = Content.Load<SpriteFont>("Fonts\\MenuText");
            op.Color = Color.Gray;
            op.AlphaValue = 255;
            op.Position = new Vector2(100, 60);
            op.IsVisible = true;
            mi = new MenuItem();
            mi.Text = op;
            mi.Activate += delegate()
            {
                int i = Player.Inventory.Weapons.IndexOf(WeaponMenu.ShownWeapon);
                if (i > 0)
                {
                    WeaponMenu.ShownWeapon = Player.Inventory.Weapons[i - 1];
                }
                else
                {
                    WeaponMenu.ShownWeapon = Player.Inventory.Weapons[Player.Inventory.Weapons.Count - 1];
                }
            };
            WeaponMenu.Options.Add(mi);

            op = new ObjectText();
            op.Text = "Equip weapon";
            op.Font = Content.Load<SpriteFont>("Fonts\\MenuText");
            op.Color = Color.Gray;
            op.AlphaValue = 255;
            op.Position = new Vector2(100, 90);
            op.IsVisible = true;
            mi = new MenuItem();
            mi.Text = op;
            mi.Activate += delegate() { 
                Player.EquippedWeapon = WeaponMenu.ShownWeapon;
                WeaponMenu.getStats();
            };
            WeaponMenu.Options.Add(mi);

            WeaponMenu.CurrentOption = mi;
            WeaponMenu.Next();
            
        }

        public void showWeaponMenu()
        {
            WeaponMenu.ShownWeapon = Player.EquippedWeapon;
            WeaponMenu.IsActive = true;            
        }

        public void hideWeaponMenu()
        {
            WeaponMenu.IsActive = false;
        }

        public void LoadLevel(string path)
        {
            Enemies = new List<Enemy>();
            Drawables = new List<IDrawable>();
            GameEnvironment = new List<GameEnvironment>();

            XmlTextReader xmlr = new XmlTextReader(path);
            while (xmlr.Read())
            {
                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Level"))
                {
                    Caption.Text = xmlr.GetAttribute("Name");
                    Caption.Position = new Vector2(graphics.Viewport.Width / 2, graphics.Viewport.Height / 5) - (Caption.Font.MeasureString(Caption.Text) / 2);
                }
                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Player"))
                {
                    Player = new Player(STANDARD_PLAYER_MODEL);

                    while (xmlr.Read())
                    {
                        if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("StartPos"))
                        {
                            Player.Position = new Vector3(float.Parse(xmlr.GetAttribute("X")), float.Parse(xmlr.GetAttribute("Y")), float.Parse(xmlr.GetAttribute("Z")));
                            Console.WriteLine("Player pos:" + Player.Position);
                        }
                        if (xmlr.NodeType == XmlNodeType.EndElement && xmlr.Name.Equals("StartPos"))
                        {
                            break;
                        }
                    }
                    Drawables.Add(player);
                    //else throw new XmlException("Ingen <StartPos> fundet under <Player>");
                }
                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Enemies"))
                {
                    while (xmlr.Read())
                    {
                        if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Enemy"))
                        {
                            Enemy enemy = new Enemy();
                            while (xmlr.Read())
                            {
                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("DropableEquipment"))
                                {
                                    while (xmlr.Read())
                                    {
                                        if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Item"))
                                        {
                                            String itemtype = xmlr.GetAttribute("type");
                                            Equipment equipment = null;
                                            if (itemtype == "Weapon")
                                            {
                                                equipment = new Weapon();
                                            }
                                            else if (itemtype == "Armor")
                                            {
                                                equipment = new Armor();
                                            }
                                            while (xmlr.Read())
                                            {
                                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("ItemModelPath"))
                                                {
                                                    String modpath = xmlr.ReadString();
                                                    equipment.ItemModel.LoadContent(modpath);
                                                }
                                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Scale"))
                                                {
                                                    float scale = float.Parse(xmlr.ReadString());
                                                    equipment.ItemModel.Scale = scale;
                                                }
                                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Stats"))
                                                {
                                                    equipment.AttackPowerBonus = Int32.Parse(xmlr.GetAttribute("attackPowerBonus"));
                                                    equipment.HpBonus = Int32.Parse(xmlr.GetAttribute("hpBonus"));
                                                    equipment.DefenceBonus = Int32.Parse(xmlr.GetAttribute("defenceBonus"));
                                                    equipment.SpeedBonus = Int32.Parse(xmlr.GetAttribute("speedBonus"));
                                                }
                                                if (xmlr.NodeType == XmlNodeType.EndElement && xmlr.Name.Equals("Item"))
                                                {
                                                    break;
                                                }
                                            }
                                            enemy.Inventory.AddItem(equipment);
                                        }
                                        if (xmlr.NodeType == XmlNodeType.EndElement && xmlr.Name.Equals("DropableEquipment"))
                                        {
                                            break;
                                        }
                                        Console.WriteLine("antal våben: " + enemy.Inventory.Weapons.Count);
                                    }
                                }
                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("StartPos"))
                                {
                                    enemy.Position = new Vector3(float.Parse(xmlr.GetAttribute("X")), float.Parse(xmlr.GetAttribute("Y")), STANDARD_ENEMY_Z);
                                }
                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("ModelPath"))
                                {
                                    enemy.CharModel.LoadContent(xmlr.ReadString());
                                }
                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Scale"))
                                {
                                    enemy.CharModel.Scale = float.Parse(xmlr.ReadString());
                                }
                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Hitpoints"))
                                {
                                    enemy.MaxHP = Int32.Parse(xmlr.ReadString());
                                    enemy.CurrentHP = enemy.MaxHP;
                                }
                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("ExperienceValue"))
                                {
                                    enemy.Experience = Int32.Parse(xmlr.ReadString());
                                }
                                if (xmlr.NodeType == XmlNodeType.EndElement && xmlr.Name.Equals("Enemy"))
                                {
                                    break;
                                }
                            }
                            Enemies.Add(enemy);
                            Drawables.Add(enemy);
                        }
                        if (xmlr.NodeType == XmlNodeType.EndElement && xmlr.Name.Equals("Enemies"))
                        {
                            break;
                        }
                    }
                }
                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Environment"))
                {
                    while (xmlr.Read())
                    {
                        if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Box"))
                        {
                            Box box = new Box();
                            while (xmlr.Read())
                            {
                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Position"))
                                {
                                    box.Position = new Vector3(float.Parse(xmlr.GetAttribute("X")), float.Parse(xmlr.GetAttribute("Y")), float.Parse(xmlr.GetAttribute("Z")));
                                    Console.WriteLine("pos:" + box.Position);
                                }
                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("ModelPath"))
                                {
                                    String modpath = xmlr.ReadString();
                                    box.EnvModel.LoadContent(modpath);
                                }
                                if (xmlr.NodeType == XmlNodeType.Element && xmlr.Name.Equals("Scale"))
                                {
                                    box.EnvModel.Scale = float.Parse(xmlr.ReadString());
                                }
                                if (xmlr.NodeType == XmlNodeType.EndElement && xmlr.Name.Equals("Box"))
                                {
                                    break;
                                }
                            }
                            GameEnvironment.Add(box);
                            Drawables.Add(box);
                        }
                        if (xmlr.NodeType == XmlNodeType.EndElement && xmlr.Name.Equals("Environment"))
                        {
                            break;
                        }
                    }
                }
            }
            xmlr.Close();
            foreach (IDrawable drawable in Drawables)
            {
                Console.WriteLine("Test: " + drawable.GetType());
            }

            PlayerInitialize();
            Camera = new Camera();
            Camera.DefaultCamera();

            hideGameLevel();
            createMenues();
            showGameLevel();
            
        }

    }
}
